package com.yuntsg.ruiijn.paperana.utils.esutils;

import cn.hutool.http.HttpUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import co.elastic.clients.json.JsonData;
import com.alibaba.fastjson.JSONObject;
import com.yuntsg.ruiijn.paperana.utils.SmallTool;
import com.yuntsg.ruiijn.paperana.utils.StrUtils;
import common.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @Author: gcr
 * @Date: 2023/8/30 15:49
 */

@Component
@Slf4j
public class EsSearch {
    @Autowired
    private ElasticsearchClient client;
    @Value("${central.api.url}")
    public String escenterUrl;

    // 检索测试 2023年8月30日15:51:20
    @SneakyThrows
    public void main(String[] args) {

        String lucen = "Folate might counteract the effects of environmental chemical exposures.";
        String lucen1 = "Folate might counteract the effects of environmental ";
        String lucen2 = "Folate might counteract the effects ";
        String lucen3 = "of environmental chemical exposures.";
        String lucen4 = "counteract the effects of environmental chemical exposures.";

        SearchRequest.Builder builder = new SearchRequest.Builder();
        BoolQuery.Builder allQueryBuilder = new BoolQuery.Builder();
//        allQueryBuilder.must(MatchQuery.of(i -> i.field("strcntest").query(lucen))._toQuery());
//        allQueryBuilder.must(MatchQuery.of(i -> i.field("strcntest").query(lucen1))._toQuery());
        allQueryBuilder.must(MatchQuery.of(i -> i.field("strcntest").query(lucen2))._toQuery());
//        allQueryBuilder.must(MatchQuery.of(i -> i.field("strcntest").query(lucen3))._toQuery());
//        allQueryBuilder.must(MatchQuery.of(i -> i.field("strcntest").query(lucen4))._toQuery());
//        allQueryBuilder.must(MatchQuery.of(i -> i.field("strcntest").query(lucen))._toQuery());
//        allQueryBuilder.must(MatchQuery.of(i -> i.field("strcntest").query(lucen))._toQuery());
        Query query = allQueryBuilder.build()._toQuery();
        SearchRequest searchRequest = builder.query(query)
                .trackTotalHits(k -> k.enabled(true))
                .from(0)
                .size(10)
                //.preference("_prefer_node")
                .build();

        List<EsEntity> resultList = new ArrayList<>();
        SearchResponse<EsEntity> response = client.search(searchRequest, EsEntity.class);
        List<Hit<EsEntity>> hits = response.hits().hits();
        for (Hit<EsEntity> hit : hits) {
            resultList.add(hit.source());
        }
        for (EsEntity esEntity : resultList) {
            System.out.println(esEntity.getId());
            System.out.println(esEntity.getStrcntest());
            System.out.println("++++++++++++++++++++++++++");
        }
        // 初步是可以模糊检索到 2023年8月30日16:14:30
        // EsClient.clientOff();

    }


//    /**
//     * @param cla     类型
//     * @param colname 查询字段
//     * @param str     查询字符
//     * @param <T>     泛型
//     * @return 2023年8月31日16:47:23 通用查询方法
//     */
//    @SneakyThrows
//    public static <T> List<T> getSearchList(Class<T> cla, String colname, String str) {
//        ElasticsearchClient client = EsClient.client();
//        SearchRequest.Builder builder = new SearchRequest.Builder();
//        BoolQuery.Builder allQueryBuilder = new BoolQuery.Builder();
//        allQueryBuilder.must(MatchQuery.of(i -> i.field(colname).query(str))._toQuery());
//        Query query = allQueryBuilder.build()._toQuery();
//        SearchRequest searchRequest = builder.query(query)
//                .trackTotalHits(k -> k.enabled(true))
//                .from(0)
//                .size(10)
//                //.preference("_prefer_node")
//                .build();
//        List<T> resultList = new ArrayList<>();
//        SearchResponse<T> response = client.search(searchRequest, cla);
//        List<Hit<T>> hits = response.hits().hits();
//        for (Hit<T> hit : hits) {
//            resultList.add(hit.source());
//        }
//        return resultList;
//    }


    /**
     * @param str 查询字符
     * @return 2023年9月5日14:31:40 童工es 文章检索  通用查询方法
     */
    @SneakyThrows
    public List<EsServerEntity> esSearchTong(ElasticsearchClient esClient,
                                             String str,
                                             Integer fid, Integer uid, Integer splitAs, String esSimilar, String artyear, String pmut) {

        if (StringUtil.isNull(artyear)) {
            artyear = "";
        }

        if (StringUtil.isNull(pmut)) {
            pmut = "";
        }

        List<EsServerEntity> res = new ArrayList<>();
        try {
            //es 检索句子 默认60%
            String txtSimilar = "60%";
            if (StringUtil.isNull(esSimilar)) {
                esSimilar = txtSimilar;
            }

            String finalEsSimilar = esSimilar;
            // 自定义拆分对比也用这个代码
            BoolQuery.Builder allQueryBuilder = new BoolQuery.Builder();

            if (splitAs != null && splitAs == 0) {
//            SmallTool.printMess("全网对比");
                //全网对比
                Query query = MatchQuery.of(t -> t.field("str").query(str).minimumShouldMatch(finalEsSimilar))._toQuery();
                List<String> utpmList = new ArrayList<>();
                if (StringUtil.isNotNull(pmut)) {
//                    log.info("pmut+" + pmut);
                    if (pmut.contains(",")) {
                        String[] split = pmut.split(",");
                        for (String s : split) {
                            if (StringUtil.isNotNull(s)) {
                                utpmList.add(s);
                            }
                        }
                    }
                }
                if (utpmList.size() > 0) {
                    for (String s : utpmList) {
                        Query queryPmut = MatchQuery.of(t -> t.field("pmid_ut").query(s))._toQuery();
                        allQueryBuilder.mustNot(queryPmut);
                    }
                }

                Integer checkYear;
                if (StringUtil.isNotNull(artyear)) {
                    checkYear = Integer.parseInt(artyear);
                } else {
                    checkYear = null;
                }

                if (StringUtil.isNotNull(checkYear) && checkYear.intValue() > 0) {
                    //排除后面的文章 抄袭只能抄袭以前的文章 不能抄袭未来发表的文章 对吧..
                    Query rangeQuery = RangeQuery.of(t -> t.field("year").lte(JsonData.of(checkYear)))._toQuery();
                    allQueryBuilder.must(rangeQuery);
                }
                allQueryBuilder.must(query);
            } else {
                SmallTool.printMess("自定义对比");
//                index =  IndexConfig.UNIT_INDEXTEST;
                if (StringUtil.isNotNull(fid) && StringUtil.isNotNull(uid)) {
                    Query fidsQuery = TermQuery.of(t -> t.field("file_id").value(fid))._toQuery();
                    Query tidsQuery = TermQuery.of(t -> t.field("table_id").value(uid))._toQuery();
                    List<Query> ls = new ArrayList<>();
                    ls.add(fidsQuery);
                    ls.add(tidsQuery);
                    allQueryBuilder.must(ls);
                    Query query = MatchQuery.of(t -> t.field("str").query(str).minimumShouldMatch(finalEsSimilar))._toQuery();
                    allQueryBuilder.must(query);
                }
            }
            if (splitAs != null && splitAs == 0) {
                //全网比对+++
                Map<String, Object> param = new HashMap<>();
                param.put("type", 2);
                param.put("source", null);
                param.put("page", null);
                param.put("content", str);
                param.put("artyear", artyear);
                param.put("pmut", pmut);
//                log.info("pmut++"+pmut);
//                log.info("artyear++"+artyear);
                String post = HttpUtil.post(escenterUrl + "web/pub/getes", param);
                Map<String, Object> stringObjectMap = JSONObject.parseObject(post, Map.class);
                List<EsServerEntity> hits = new ArrayList<>();
                if (Integer.parseInt(stringObjectMap.get("code").toString()) == 0) {
                    String data = JSONObject.toJSONString(stringObjectMap.get("data"));
                    data = data.substring(1, data.length() - 1);
                    hits = JSONObject.parseArray(data, EsServerEntity.class);
                }
//                log.info("web/pub/getes+size+"+hits.size());
                for (EsServerEntity hit : hits) {

                    Map<String, List<String>> highlight = hit.getHighlight();
                    StringBuffer news = new StringBuffer();
                    highlight.forEach((k, v) -> {
                        for (String s : v) {
                            news.append(s + " ");
                        }
                    });
                    hit.setESid(hit.getESid());
                    hit.setStrMatchRed(news.toString());
                    boolean b = StrUtils.checkSentence(str, hit.getStrMatchRed());
                    if (b) {
                        res.add(hit);
                    }
                }
            } else {
                String finalIndex = IndexConfig.SELF_TETX_INDEX;

                SearchResponse<EsServerEntity> response = esClient.search(s -> s
                                .index(finalIndex)
                                .fields(Arrays.asList(
                                        FieldAndFormat.of(builder -> builder.field("file_id")),
                                        FieldAndFormat.of(builder -> builder.field("sentence")),
                                        FieldAndFormat.of(builder -> builder.field("database_type")),
                                        FieldAndFormat.of(builder -> builder.field("str")),
                                        FieldAndFormat.of(builder -> builder.field("sub_project")),
                                        FieldAndFormat.of(builder -> builder.field("table_id"))))
                                .from(0)
                                .size(10)
                                .highlight(h -> h.preTags("<span style=\"color:red\">").postTags("</span>").fields("str", highlightFieldBuilder -> highlightFieldBuilder))
                                .query(allQueryBuilder.build()._toQuery()),
                        EsServerEntity.class
                );
                List<Hit<EsServerEntity>> hits = response.hits().hits();
                for (Hit<EsServerEntity> hit : hits) {
                    EsServerEntity source = hit.source();
                    Map<String, List<String>> highlight = hit.highlight();
                    StringBuffer news = new StringBuffer();
                    highlight.forEach((k, v) -> {
                        for (String s : v) {
                            news.append(s + " ");
                        }
                    });
                    source.setESid(hit.id());
                    source.setStrMatchRed(news.toString());
                    boolean b = StrUtils.checkSentence(str, source.getStrMatchRed());
                    if (b) {
                        res.add(source);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return res;
    }

    // 检测客户机器可以访问远程 es全库吗 吗?
    public boolean checkCustomEsRemoteEs() {
        String str = "For breast reduction, purchasing restric- tions appear";
        String artyear = "";
        String pmut = "";
        Map<String, Object> param = new HashMap<>();
        param.put("type", 2);
        param.put("source", null);
        param.put("page", null);
        param.put("content", str);
        param.put("artyear", artyear);
        param.put("pmut", pmut);
        String post = HttpUtil.post(escenterUrl + "web/pub/getes", param);
        Map<String, Object> stringObjectMap = JSONObject.parseObject(post, Map.class);
        List<EsServerEntity> hits = new ArrayList<>();
        if (Integer.parseInt(stringObjectMap.get("code").toString()) == 0) {
            String data = JSONObject.toJSONString(stringObjectMap.get("data"));
            try {
                String datamEW = data.substring(1, data.length() - 1);
                hits = JSONObject.parseArray(datamEW, EsServerEntity.class);
            } catch (Exception e) {
//                e.printStackTrace();
//                log.info("v2");
                hits = JSONObject.parseArray(data, EsServerEntity.class);
            }
        }
        if (hits.size() > 0) {
            return true;
        } else {
            return false;
        }
    }

    //  用于检测全网文字库可用吗
    @SneakyThrows
    public boolean checkOnlineEsIsAVA(ElasticsearchClient esClient) {
        SmallTool.printMess("检测es库++" + IndexConfig.PUB_TEXT_INDEX);
        // 客户机器本机没有本地es全网库 需要进行拆分处理
        if (StrUtils.checkIsMyServer()) {
            if (esClient.indices().exists(b -> b.index(IndexConfig.PUB_TEXT_INDEX)).value()) {
                SmallTool.printMess("es 存在进行判断数量++" + IndexConfig.PUB_TEXT_INDEX);
                SearchResponse<Object> response = esClient.search(s -> s
                                .index(IndexConfig.PUB_TEXT_INDEX).size(3),
                        Object.class
                );
                TotalHits total = response.hits().total();
                System.out.println(total.value());
                if (total.value() != 0L) {
                    SmallTool.printMess("es数量不是空");
                    return true;
                } else {
                    SmallTool.printMess("es 库是空");
                    return false;
                }
            } else {
                SmallTool.printMess("es 不存在?");
                return false;
            }
        } else {
            return checkCustomEsRemoteEs();
        }

    }

    /**
     * @param str 查询字符
     * @return 2024年4月28日09:50:47 童工es  这是上传文章与自己的自定义文字库进行比对
     * <p>
     * * @param fid        file_id  记录表的主键id 表格主键 -> 变成了数据库字段 注意查看 指的TextSelfDb id
     * * @param uid        table_id  ncbi_pdf_to_txt_101 表名的后缀101 -> 指的 指的 TextSelfDb uid
     */
    @SneakyThrows
    public List<EsServerEntity> getSearchListTongSelf(String ids, ElasticsearchClient esClient,
                                                      String str,
                                                      Integer uid, String esSimilar) {
        //es 检索句子 默认60%
        String txtSimilar = "60%";
        if (StringUtil.isNull(esSimilar)) {
            esSimilar = txtSimilar;
        }
        String finalEsSimilar = esSimilar;
//        System.out.println("fid+"+fid);
//        System.out.println("uid+"+uid);
//        System.out.println("ids+"+ids);
        // 自定义拆分对比也用这个代码
        BoolQuery.Builder allQueryBuilder = new BoolQuery.Builder();
        List<EsServerEntity> res = new ArrayList<>();
        String index = IndexConfig.SELF_TETX_INDEX;
//        if (StringUtil.isNotNull(fid) && StringUtil.isNotNull(uid)) {
        if (StringUtil.isNotNull(uid)) {
            Query tidsQuery;
            if (StringUtil.isNotNull(ids)) {
                List<String> list = Arrays.asList(ids.split(","));
                List<FieldValue> values = new ArrayList<>();
                for (String s : list) {
                    values.add(FieldValue.of(s));
                }
                tidsQuery = TermsQuery.of(t -> t.field("file_id").terms(new TermsQueryField.Builder()
                        .value(values).build()
                ))._toQuery();
            } else {
                tidsQuery = TermQuery.of(t -> t.field("table_id").value(uid))._toQuery();
            }
            List<Query> ls = new ArrayList<>();
            ls.add(tidsQuery);
            allQueryBuilder.must(ls);
            Query query = MatchQuery.of(t -> t.field("str").query(str).minimumShouldMatch(finalEsSimilar))._toQuery();
            allQueryBuilder.must(query);
        } else {
            // 2024年10月29日15:39:23 目前还没搞定前后台用户传文件导致的查询不到数据 默认全部放开
            Query query = MatchQuery.of(t -> t.field("str").query(str).minimumShouldMatch(finalEsSimilar))._toQuery();
            allQueryBuilder.must(query);
        }
        String finalIndex = index;
        SearchResponse<EsServerEntity> response = esClient.search(s -> s
                        .index(finalIndex)
                        .fields(Arrays.asList(
                                FieldAndFormat.of(builder -> builder.field("file_id")),
                                FieldAndFormat.of(builder -> builder.field("sentence")),
                                FieldAndFormat.of(builder -> builder.field("database_type")),
                                FieldAndFormat.of(builder -> builder.field("str")),
                                FieldAndFormat.of(builder -> builder.field("sub_project")),
                                FieldAndFormat.of(builder -> builder.field("table_id"))))
                        .from(0)
                        .size(10)
                        .highlight(h -> h.preTags("<span style=\"color:red\">").postTags("</span>").fields("str", highlightFieldBuilder -> highlightFieldBuilder))
                        .query(allQueryBuilder.build()._toQuery()),
                EsServerEntity.class
        );
        List<Hit<EsServerEntity>> hits = response.hits().hits();
        for (Hit<EsServerEntity> hit : hits) {
            EsServerEntity source = hit.source();
            Map<String, List<String>> highlight = hit.highlight();
            StringBuffer news = new StringBuffer();
            highlight.forEach((k, v) -> {
                for (String s : v) {
                    news.append(s + " ");
                }
            });
            source.setESid(hit.id());
            source.setStrMatchRed(news.toString());
            res.add(source);
        }
        return res;
    }


    //  用于检测本地文字库可用吗
    @SneakyThrows
    public boolean checkLocalEsIsAVA(ElasticsearchClient esClient) {
        SmallTool.printMess("检测es库++" + IndexConfig.SELF_TETX_INDEX);
        if (esClient.indices().exists(b -> b.index(IndexConfig.SELF_TETX_INDEX)).value()) {
            SmallTool.printMess("es 存在进行判断数量++" + IndexConfig.SELF_TETX_INDEX);
            SearchResponse<Object> response = esClient.search(s -> s
                            .index(IndexConfig.SELF_TETX_INDEX).size(3),
                    Object.class
            );
            TotalHits total = response.hits().total();
            System.out.println(total.value());
            if (total.value() != 0L) {
                SmallTool.printMess("es数量不是空");
                return true;
            } else {
                SmallTool.printMess("es 库是空");
                return false;
            }
        } else {
            SmallTool.printMess("es 不存在?");
            return false;
        }
    }

}
